package com.netflexitysolutions.amazonws.ec2;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.amazonaws.ec2.doc._2009_04_04.AmazonEC2PortType;
import com.netflexitysolutions.amazonws.ec2.internal.operations.AllocateAddressOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.AssociateAddressOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.AttachVolumeOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.AuthorizeSecurityGroupIngressOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.BundleInstanceOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.CancelBundleTaskOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.ConfirmProductInstanceOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.CreateKeyPairOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.CreateSecurityGroupOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.CreateSnapshotOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.CreateVolumeOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DeleteKeyPairOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DeleteSecurityGroupOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DeleteSnapshotOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DeleteVolumeOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DeregisterImageOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DescribeAddressesOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DescribeAvailabilityZonesOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DescribeBundleTasksOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DescribeImageAttributeOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DescribeImagesOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DescribeInstancesOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DescribeKeyPairsOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DescribeRegionsOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DescribeReservedInstancesOfferingsOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DescribeReservedInstancesOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DescribeSecurityGroupsOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DescribeSnapshotsOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DescribeVolumesOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DetachVolumeOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.DisassociateAddressOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.GetConsoleOutputOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.ModifyLaunchPermissionsOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.MonitorInstancesOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.OperationExecutor;
import com.netflexitysolutions.amazonws.ec2.internal.operations.PurchaseReservedInstancesOfferingOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.RebootInstancesOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.RegisterImageOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.ReleaseAddressOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.ResetImageAttributeOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.RevokeSecurityGroupIngressOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.RunInstancesOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.SetProductCodeOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.TerminateInstancesOperation;
import com.netflexitysolutions.amazonws.ec2.internal.operations.UnmonitorInstancesOperation;

/**
 * @author lordorient
 *
 */
public class EC2Client implements EC2 {
	
	private AmazonEC2PortType service;	

	/**
	 * @param service
	 */
	public EC2Client(AmazonEC2PortType service) {
		this.service = service;
	}
	
	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#deregisterImage(java.lang.String)
	 */
	public boolean deregisterImage(String imageId) throws EC2Exception {
		DeregisterImageOperation operation = new DeregisterImageOperation(this, imageId);
		return operation.execute();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#describeImages(java.util.Set, java.util.Set, java.util.Set)
	 */
	public List<ImageDescription> describeImages(Set<String> imageIds,
			Set<String> ownedBy, Set<String> executableBy) throws EC2Exception {
		DescribeImagesOperation operation =  new DescribeImagesOperation(this, imageIds, ownedBy, executableBy);
		return operation.execute();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#registerImage(java.lang.String)
	 */
	public String registerImage(String pathToImage) throws EC2Exception {
		RegisterImageOperation operation = new RegisterImageOperation(this, pathToImage); 
		return operation.execute();
	}
	
	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#getBlockDeviceMappings(java.lang.String)
	 */
	@SuppressWarnings({"unchecked"})
	public List<BlockDeviceMapping> getBlockDeviceMappings(String imageId) throws EC2Exception {
		return (List<BlockDeviceMapping>)getImageAttributeInt(imageId, ImageAttributeType.BLOCK_DEVICE_MAPPING);
	}
	
	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#getLaunchPermitions(java.lang.String)
	 */
	@SuppressWarnings({"unchecked"})
	public List<LaunchPermission> getLaunchPermitions(String imageId) throws EC2Exception {
		return (List<LaunchPermission>)getImageAttributeInt(imageId, ImageAttributeType.LAUNCH_PERMISSION);
	}
	
	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#getProductCodes(java.lang.String)
	 */
	@SuppressWarnings({"unchecked"})
	public List<String> getProductCodes(String imageId) throws EC2Exception {
		return (List<String>)getImageAttributeInt(imageId, ImageAttributeType.PRODUCT_CODES);
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#getSimpleAttribute(java.lang.String, com.netflexitysolutions.amazonws.ec2.SimpleAttributeType)
	 */
	public String getSimpleAttribute(String imageId, ImageSimpleAttributeType type) throws EC2Exception {
		return (String)getImageAttributeInt(imageId, type.getMasterType());
	}
	
	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#addLaunchPermission(java.lang.String, com.netflexitysolutions.amazonws.ec2.LaunchPermission)
	 */
	public boolean addLaunchPermission(String imageId,
			LaunchPermission permission) throws EC2Exception {
		List<LaunchPermission> list = new ArrayList<LaunchPermission>();
		list.add(permission);
		return addLaunchPermissions(imageId, list);
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#addLaunchPermissions(java.lang.String, java.util.List)
	 */
	public boolean addLaunchPermissions(String imageId, List<LaunchPermission> permissions) throws EC2Exception {
		ModifyLaunchPermissionsOperation operation = 
			new ModifyLaunchPermissionsOperation(this, imageId, permissions, ModifyLaunchPermissionsOperation.Action.ADD);
		return operation.execute();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#removeLaunchPermission(java.lang.String, com.netflexitysolutions.amazonws.ec2.LaunchPermission)
	 */
	public boolean removeLaunchPermission(String imageId,
			LaunchPermission permission) throws EC2Exception {
		List<LaunchPermission> list = new ArrayList<LaunchPermission>();
		list.add(permission);
		return removeLaunchPermissions(imageId, list);
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#removeLaunchPermissions(java.lang.String, java.util.List)
	 */
	public boolean removeLaunchPermissions(String imageId, List<LaunchPermission> permissions) throws EC2Exception {
		ModifyLaunchPermissionsOperation operation = 
			new ModifyLaunchPermissionsOperation(this, imageId, permissions, ModifyLaunchPermissionsOperation.Action.REMOVE);
		return operation.execute();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#setProductCode(java.lang.String, java.lang.String)
	 */
	public boolean setProductCode(String imageId, String productCode) throws EC2Exception {
		SetProductCodeOperation operation =  new SetProductCodeOperation(this, imageId, productCode);
		return operation.execute();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#resetImageAttribute(java.lang.String, com.netflexitysolutions.amazonws.ec2.ImageAttributeType)
	 */
	public boolean resetImageAttribute(String imageId, ImageAttributeType attribute) throws EC2Exception {
		ResetImageAttributeOperation operation = new ResetImageAttributeOperation(this, imageId, attribute);
		return operation.execute();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#describeInstance(java.lang.String)
	 */
	public RunningInstance describeInstance(String instanceId) throws EC2Exception {
		Set<String> ids = new HashSet<String>();
		if (instanceId != null) {
			ids.add(instanceId);
		}
		return describeInstances(ids).get(0);
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#describeInstances(java.util.List)
	 */
	public List<RunningInstance> describeInstances(Set<String> instanceIds) throws EC2Exception {
		DescribeInstancesOperation operation = new DescribeInstancesOperation(this, instanceIds);
		return operation.execute();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#rebootInstances(java.util.Set)
	 */
	public boolean rebootInstances(Set<String> instanceIds) throws EC2Exception {
		RebootInstancesOperation operation = new RebootInstancesOperation(this, instanceIds);
		return operation.execute();
	}

	public InstanceTerminationResult terminateInstance(String instanceId) throws EC2Exception {
		Set<String> ids = new HashSet<String>();
		if (instanceId != null) {
			ids.add(instanceId);
		}
		return terminateInstances(ids).get(0);
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#terminateInstances(java.util.Set)
	 */
	public List<InstanceTerminationResult> terminateInstances(Set<String> instanceIds) throws EC2Exception {
		TerminateInstancesOperation operation = new TerminateInstancesOperation(this, instanceIds);
		return operation.execute();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#runInstances(com.netflexitysolutions.amazonws.ec2.InstanceStartupParameters)
	 */
	public List<RunningInstance> runInstances(InstanceStartupParameters params) throws EC2Exception {
		RunInstancesOperation operation = new RunInstancesOperation(this, params);
		return operation.execute();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#describeReservedInstances(java.util.Set)
	 */
	public List<ReservedInstances> describeReservedInstances(Set<String> instanceIds) throws EC2Exception {
		DescribeReservedInstancesOperation operation = new DescribeReservedInstancesOperation(this, instanceIds);
		return operation.execute();
	}

	public List<ReservedInstancesOffering> describeReservedInstancesOfferings(
			Set<String> instancesOfferingIds, InstanceType instanceType,
			String availabilityZone, String productDescription)
			throws EC2Exception {
		DescribeReservedInstancesOfferingsOperation operation =  new DescribeReservedInstancesOfferingsOperation(this, 
					instancesOfferingIds, instanceType, availabilityZone, productDescription);
		return operation.execute();
	}

	public String purchaseReservedInstancesOffering(
			String reservedInstancesOfferingId) throws EC2Exception {
		PurchaseReservedInstancesOfferingOperation operation
							= new PurchaseReservedInstancesOfferingOperation(this, reservedInstancesOfferingId, null);
		return operation.execute();
	}

	public String purchaseReservedInstancesOffering(
			String reservedInstancesOfferingId, int instanceCount)
			throws EC2Exception {
		PurchaseReservedInstancesOfferingOperation operation
							= new PurchaseReservedInstancesOfferingOperation(this, reservedInstancesOfferingId, instanceCount);
		return operation.execute();
	}

	////////////////////////////////
	// Security groups operations //
	////////////////////////////////

	public List<SecurityGroup> describeSecurityGroups() throws EC2Exception {
		return describeSecurityGroups(new HashSet<String>());
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#describeSecurityGroups(java.util.Set)
	 */
	public List<SecurityGroup> describeSecurityGroups(Set<String> groupNames) throws EC2Exception {
		DescribeSecurityGroupsOperation operation = new DescribeSecurityGroupsOperation(this, groupNames);
		return operation.execute();
	}
	
	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#createSecurityGroup(java.lang.String, java.lang.String)
	 */
	public boolean createSecurityGroup(String name, String description) throws EC2Exception {
		CreateSecurityGroupOperation operation = new CreateSecurityGroupOperation(this, name, description);
		return operation.execute();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#deleteSecurityGroup(java.lang.String)
	 */
	public boolean deleteSecurityGroup(String name) throws EC2Exception {
		DeleteSecurityGroupOperation operation = new DeleteSecurityGroupOperation(this, name);
		return operation.execute();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#authorizeSecurityGroupIngress(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
	 */
	public boolean authorizeSecurityGroupIngress(String userId,
			String groupName, String secGroupOwnerId, String secGroupName)
			throws EC2Exception {
		IPPermission permission = new IPPermission();
		permission.getUserIdGroupPairs().add(new UserIdGroupPair(secGroupOwnerId, secGroupName));
		AuthorizeSecurityGroupIngressOperation operation 
					= new AuthorizeSecurityGroupIngressOperation(this, userId, groupName, permission);
		return operation.execute();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#authorizeSecurityGroupIngress(java.lang.String, java.lang.String, com.netflexitysolutions.amazonws.ec2.IPProtocol, int, int, java.lang.String)
	 */
	public boolean authorizeSecurityGroupIngress(String userId,
			String groupName, IPProtocol ipProtocol, int fromPort, int toPort,
			String cidrIp) throws EC2Exception {
		IPPermission permission = new IPPermission();
		permission.setFromPort(fromPort);
		permission.setToPort(toPort);
		permission.setProtocol(ipProtocol);
		permission.getIpRanges().add(cidrIp);
		AuthorizeSecurityGroupIngressOperation operation 
					= new AuthorizeSecurityGroupIngressOperation(this, userId, groupName, permission);
		return operation.execute();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#revokeSecurityGroupIngress(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
	 */
	public boolean revokeSecurityGroupIngress(String userId,
			String groupName, String secGroupOwnerId, String secGroupName)
			throws EC2Exception {
		IPPermission permission = new IPPermission();
		permission.getUserIdGroupPairs().add(new UserIdGroupPair(secGroupOwnerId, secGroupName));
		RevokeSecurityGroupIngressOperation operation 
					= new RevokeSecurityGroupIngressOperation(this, userId, groupName, permission);
		return operation.execute();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#revokeSecurityGroupIngress(java.lang.String, java.lang.String, com.netflexitysolutions.amazonws.ec2.IPProtocol, int, int, java.lang.String)
	 */
	public boolean revokeSecurityGroupIngress(String userId,
			String groupName, IPProtocol ipProtocol, int fromPort, int toPort,
			String cidrIp) throws EC2Exception {
		IPPermission permission = new IPPermission();
		permission.setFromPort(fromPort);
		permission.setToPort(toPort);
		permission.setProtocol(ipProtocol);
		permission.getIpRanges().add(cidrIp);
		RevokeSecurityGroupIngressOperation operation 
					= new RevokeSecurityGroupIngressOperation(this, userId, groupName, permission);
		return operation.execute();
	}

	//////////////////////////
	// Key pairs operations //
	//////////////////////////
	
	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#createKeyPair(java.lang.String)
	 */
	public KeyPair createKeyPair(String keyName) throws EC2Exception {
		CreateKeyPairOperation operation = new CreateKeyPairOperation(this, keyName);
		return operation.execute();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#deleteKeyPair(java.lang.String)
	 */
	public boolean deleteKeyPair(String keyName) throws EC2Exception {
		DeleteKeyPairOperation operation = new DeleteKeyPairOperation(this, keyName);
		return operation.execute();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#describeKeyPairs()
	 */
	public List<KeyPair> describeKeyPairs() throws EC2Exception {
		return describeKeyPairs(new HashSet<String>());
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#describeKeyPairs(java.util.List)
	 */
	public List<KeyPair> describeKeyPairs(Set<String> keyNames)
			throws EC2Exception {
		DescribeKeyPairsOperation operation = new DescribeKeyPairsOperation(this, keyNames);
		return operation.execute();
	}

	//////////////////////////////////
	// zones and regions operations //
	//////////////////////////////////

	public List<AvailabilityZone> describeAvailabilityZones() throws EC2Exception {
		return describeAvailabilityZones(new HashSet<String>());
	}

	public List<AvailabilityZone> describeAvailabilityZones(
			Set<String> zoneNames) throws EC2Exception {
		DescribeAvailabilityZonesOperation operation = new DescribeAvailabilityZonesOperation(this, zoneNames);
		return operation.execute();
	}

	public List<Region> describeRegions() throws EC2Exception {
		return describeRegions(new HashSet<String>());
	}

	public List<Region> describeRegions(Set<String> regionNames) throws EC2Exception {
		DescribeRegionsOperation operation = new DescribeRegionsOperation(this, regionNames);
		return operation.execute();
	}

	////////////////////////////
	// block store operations //
	////////////////////////////

	public AttachmentInfo attachVolume(String volumeId, String instanceId,
			String device) throws EC2Exception {
		AttachVolumeOperation operation = new AttachVolumeOperation(this, volumeId, instanceId, device);
		return operation.execute();
	}

	public Snapshot createSnapshot(String volumeId) throws EC2Exception {
		CreateSnapshotOperation operation = new CreateSnapshotOperation(this, volumeId);
		return operation.execute();
	}

	public Volume createVolume(int size, String availabilityZoneName)
			throws EC2Exception {
		CreateVolumeOperation operation = new CreateVolumeOperation(this, null, Integer.toString(size), availabilityZoneName);
		return operation.execute();
	}

	public Volume createVolume(String snapshotId, String availabilityZoneName)
			throws EC2Exception {
		CreateVolumeOperation operation = new CreateVolumeOperation(this, snapshotId, null, availabilityZoneName);
		return operation.execute();
	}

	public boolean deleteSnapshot(String snapshotId) throws EC2Exception {
		DeleteSnapshotOperation operation =  new DeleteSnapshotOperation(this, snapshotId);
		return operation.execute();
	}

	public boolean deleteVolume(String volumeId) throws EC2Exception {
		DeleteVolumeOperation operation =  new DeleteVolumeOperation(this, volumeId);
		return operation.execute();
	}

	public List<Snapshot> describeSnapshots() throws EC2Exception {
		return describeSnapshots(new HashSet<String>());
	}

	public List<Snapshot> describeSnapshots(Set<String> snapshotIds)
			throws EC2Exception {
		DescribeSnapshotsOperation operation =  new DescribeSnapshotsOperation(this, snapshotIds);
		return operation.execute();
	}

	public List<Volume> describeVolumes() throws EC2Exception {
		return describeVolumes(new HashSet<String>());
	}

	public List<Volume> describeVolumes(Set<String> volumeIds) throws EC2Exception {
		DescribeVolumesOperation operation = new DescribeVolumesOperation(this, volumeIds);
		return operation.execute();
	}

	public AttachmentInfo detachVolume(String volumeId, String instanceId,
			String device, boolean force) throws EC2Exception {
		return detachVolumeInt(volumeId, instanceId, device, force);
	}

	public AttachmentInfo detachVolume(String volumeId, String instanceId,
			String device) throws EC2Exception {
		return detachVolumeInt(volumeId, instanceId, device, null);
	}

	///////////////////////////
	// elastic ip operations //
	///////////////////////////
	
	public String allocateAddress() throws EC2Exception {
		AllocateAddressOperation operation = new AllocateAddressOperation(this);
		return operation.execute();
	}

	public boolean associateAddress(String instanceId, String publicIp)
			throws EC2Exception {
		AssociateAddressOperation operation = new AssociateAddressOperation(this, instanceId, publicIp);
		return operation.execute();
	}

	public List<Address> describeAddresses() throws EC2Exception {
		return describeAddresses(new HashSet<String>());
	}

	public List<Address> describeAddresses(Set<String> publicIps)
			throws EC2Exception {
		DescribeAddressesOperation operation =  new DescribeAddressesOperation(this, publicIps);
		return operation.execute();
	}

	public boolean disassociateAddress(String publicIp) throws EC2Exception {
		DisassociateAddressOperation operation = new DisassociateAddressOperation(this, publicIp);
		return operation.execute();
	}

	public boolean releaseAddress(String publicIp) throws EC2Exception {
		ReleaseAddressOperation operation = new ReleaseAddressOperation(this, publicIp);
		return operation.execute();
	}

	///////////////////
	// Amazon DevPay //
	///////////////////
	
	public String confirmProductInstance(String productCode, String instanceId) throws EC2Exception {
		ConfirmProductInstanceOperation operation = new ConfirmProductInstanceOperation(this, productCode, instanceId);
		return operation.execute();
	}

	/////////////
	// General //
	/////////////
	
	public ConsoleOutput getConsoleOutput(String instanceId) throws EC2Exception {
		GetConsoleOutputOperation operation = new GetConsoleOutputOperation(this, instanceId);
		return operation.execute();
	}

	////////////////
	// Monitoring //
	////////////////
	
	public List<InstanceMonitoringInfo> monitorInstances(Set<String> instanceIds) throws EC2Exception {
		MonitorInstancesOperation operation = new MonitorInstancesOperation(this, instanceIds);
		return operation.execute();
	}

	public List<InstanceMonitoringInfo> unmonitorInstances(Set<String> instanceIds) throws EC2Exception {
		UnmonitorInstancesOperation operation = new UnmonitorInstancesOperation(this, instanceIds);
		return operation.execute();
	}

	public InstanceMonitoringInfo monitorInstance(String instanceId) throws EC2Exception {
		Set<String> set = new HashSet<String>();
		set.add(instanceId);
		List<InstanceMonitoringInfo> list = monitorInstances(set);
		//TODO: what if incorrect instanceId supplied and empty list returned
		return list.get(0);
	}

	public InstanceMonitoringInfo unmonitorInstance(String instanceId) throws EC2Exception {
		Set<String> set = new HashSet<String>();
		set.add(instanceId);
		List<InstanceMonitoringInfo> list = unmonitorInstances(set);
		//TODO: what if incorrect instanceId supplied and empty list returned
		return list.get(0);
	}

	/////////////
	// Windows //
	/////////////
	
	public BundleInstanceInfo bundleInstance(String instanceId,
			String bucketId, String prefix, String awsAccessKeyId,
			String awsSecretKey) throws EC2Exception {
		BundleInstanceOperation operation = new BundleInstanceOperation(this, instanceId,
				bucketId, prefix, awsAccessKeyId, awsSecretKey);
		return operation.execute();
	}
	
	public BundleInstanceInfo cancelBundleTask(String bundleId) throws EC2Exception {
		CancelBundleTaskOperation operation = new CancelBundleTaskOperation(this, bundleId);
		return operation.execute();
	}

	public List<BundleInstanceInfo> describeBundleTasks() throws EC2Exception {
		return describeBundleTasks(new HashSet<String>());
	}

	public List<BundleInstanceInfo> describeBundleTasks(Set<String> bundleIds) throws EC2Exception {
		DescribeBundleTasksOperation operation = new DescribeBundleTasksOperation(this, bundleIds);
		return operation.execute();
	}

	///////////////
	//  private  //
	///////////////
	
	private Object getImageAttributeInt(String imageId, ImageAttributeType type) throws EC2Exception {
		DescribeImageAttributeOperation operation = new DescribeImageAttributeOperation(this, imageId, type);
		return operation.execute();
	}
	
	private AttachmentInfo detachVolumeInt(String volumeId, String instanceId,
			String device, Boolean force) throws EC2Exception {
		DetachVolumeOperation operation = new DetachVolumeOperation(this, volumeId, instanceId, device, force);
		return operation.execute();
	}

	/* (non-Javadoc)
	 * @see com.netflexitysolutions.amazonws.ec2.EC2#getService()
	 */
	public AmazonEC2PortType getService() {
		return service;
	}



}
